﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Scrutor;
using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows;
using WCS.Abstractions;

namespace WCS
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }

        [STAThread]
        public static void Main()
        {
            var builder = new HostBuilder();

            builder.ConfigureServices(ConfigureServices);

            using (var host = builder.Build())
            {
                host.Start();

                var window = host.Services.GetRequiredKeyedService<Window>("MainWindow");

                new App().Run(window);
            }
        }

        private static void ConfigureServices(HostBuilderContext context, IServiceCollection services)
        {
            ConfigureLoggingServices(services);
            SacnServices(context, services);
        }

        private static void ConfigureLoggingServices(IServiceCollection services)
        {
            services.AddLogging(configure =>
            {
                configure.ClearProviders();

                Log.Logger = new LoggerConfiguration()
                    .Enrich.FromLogContext()
                    .WriteTo.File
                    (
                        "logs\\wcs.log",
                        fileSizeLimitBytes: 5 * 1024 * 1024,
                        rollOnFileSizeLimit: true,
                        retainedFileCountLimit: 100,
                        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] <{SourceContext}> {Message:lj}{NewLine}{Exception}"
                    ).CreateLogger();

                configure.AddSerilog(Log.Logger);
            });
        }

        private static void SacnServices(HostBuilderContext context, IServiceCollection services)
        {
            services.Scan(scaner =>
            {
                scaner.FromAssemblies(GetDependencyAssemblies(context))
                    .AddClasses(selector => selector.AssignableTo<IView>())
                    .AsSelf()
                    .UsingRegistrationStrategy(new ViewRegistrationStrategy())
                    .AddClasses(selector => selector.AssignableTo<ISingletonDependency>())
                    .AsSelf()
                    .AsImplementedInterfaces()
                    .WithSingletonLifetime()
                    .AddClasses(selector => selector.AssignableTo<IScopedDependency>())
                    .AsSelf()
                    .AsImplementedInterfaces()
                    .WithScopedLifetime()
                    .AddClasses(selector => selector.AssignableTo<ITransientDependency>())
                    .AsSelf()
                    .AsImplementedInterfaces()
                    .WithTransientLifetime();
            });
        }

        private static IEnumerable<Assembly> GetDependencyAssemblies(HostBuilderContext context)
        {
            var assemblies = new List<Assembly>()
            {
                typeof(App).Assembly
            };

            if (Directory.Exists(context.HostingEnvironment.ContentRootPath))
            {
                foreach (var file in Directory.GetFiles(context.HostingEnvironment.ContentRootPath, "*.dll"))
                {
                    assemblies.Add(Assembly.LoadFrom(file));
                }
            }

            return assemblies;
        }
    }

    internal sealed class ViewRegistrationStrategy : RegistrationStrategy
    {
        public override void Apply(IServiceCollection services, ServiceDescriptor descriptor)
        {
            services.Add(ServiceDescriptor.KeyedTransient(descriptor.ServiceType.BaseType,
                descriptor.ServiceType.Name,
                descriptor.ServiceType));
        }
    }
}
